package org.example.util;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.example.bean.User;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.io.Decoders;
import java.security.Key;
import java.util.function.Function;

@Component
public class JwtUtils {
	private static final String SECRET_KEY = "j5dfwYlEF42X7h/OdrtzWHjSk0GO8To68c8siqpsYcc="; // JWT密钥
	// 设置过期时间为 7 天
	private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 7; // 过期时间 7天

	/*
	* 1.作用： 使用 SECRET_KEY 生成签名密钥
	* 2.目的： 为了确保JWT的安全性，需要使用一个密钥来签名JWT。
	* @return 签名密钥
	* */
	private Key getSigningKey() {
		byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
		return Keys.hmacShaKeyFor(keyBytes);
	}

	/*
	 * -------------------------------提供给其他方法使用需要------------------------------------
	 * 1.作用： 生成JWT
	 * 2.目的： 用于确认用户身份的token字符串
	 * @param userDetails 用户详情
	 * @return JWT字符串
	 * -------------------------------提供给其他方法使用需要------------------------------------
	 * */
	public String generateToken(User user) {
		Map<String,Object> claims = new HashMap<>(); // 声明
		return Jwts.builder() // JWT构造器
				.addClaims(claims) // 设置声明
				.setSubject(user.getUsername()) // 将声明Sub 设置为用户名
				.setIssuedAt(new Date()) // 设置创建时间
				.setExpiration(new Date(System.currentTimeMillis()+EXPIRATION_TIME)) // 设置JWT过期时间
				.signWith(getSigningKey(), SignatureAlgorithm.HS256)
				.compact(); // 生成字符串
	}

	/*
	* 1.作用： 从JWT中提取所有声明(Claims)
	* 2.目的： 为获取用户名、过期时间、权限等信息做准备。
	* @param token JWT字符串
	* @return 所有声明
	* */
	public Claims extractAllClaim(String token) {
		return Jwts.parser() // 构建一个JWT解析器
				.setSigningKey(getSigningKey()) // 设置密钥生成的Key
				.build() // 解析器构建完成
				.parseClaimsJws(token) // 解析token
				.getBody(); // 获取到所有声明
	}

	/*
	* 1.作用： 从Claims中提取需要的值。例如用户名、过期时间、权限等信息
	* @param token JWT字符串
	* @param claimsResolver 声明解析器
	* @return 声明值
	* */
	public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
		final Claims claims = extractAllClaim(token);
		return claimsResolver.apply(claims);
	}

	/*
	* 1.作用： 从Claims中获取 用户名
	* 相当于
	* public String extractUserName(String token) {
	*	 Claims claims = extractAllClaim(token);
	*	 return claims.getSubject();
	* }
	*/
	public String extractUserName(String token) {
		return extractClaim(token, Claims::getSubject);
	}

	/*
	* 1.作用： 获取JWT的过期时间
	* @param token JWT字符串
	* @return 过期时间
	* */
	public Date extractExpiration(String token) {
		return extractClaim(token,Claims::getExpiration);
	}

	/*
	* 1.作用： 判断JWT是否过期
	* @param token JWT字符串
	* @return true 过期    false 未过期
	* */
	public Boolean isTokenExpired(String token) {
		// 声明过期时间在当前时间之前则返回true
		return extractExpiration(token).before(new Date()); // 判断声明过期时间是否在当前时间之前
	}

	/*
	* -------------------------------提供给其他方法使用需要------------------------------------
	* 1.作用： 验证用户传输的JWT是否有效(确保JWT未过期，并且用户名与用户详情中的用户名一致)
	* @param token JWT字符串
	* @param userDetails 用户详情
	* @return true 有效    false 无效
	* -------------------------------提供给其他方法使用需要------------------------------------
	*/
	public Boolean validateToken(String token, User user) {
		System.out.println(user.getUsername().equals(extractUserName(token)));
		System.out.println(!isTokenExpired(token));
		return (user.getUsername().equals(extractUserName(token))) && !isTokenExpired(token);
	}
}
